home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-04 / gs24src.zip / ZCHAR.C < prev    next >
C/C++ Source or Header  |  1991-12-04  |  15KB  |  522 lines

  1. /* Copyright (C) 1989, 1990, 1991 Aladdin Enterprises.  All rights reserved.
  2.    Distributed by Free Software Foundation, Inc.
  3.  
  4. This file is part of Ghostscript.
  5.  
  6. Ghostscript is distributed in the hope that it will be useful, but
  7. WITHOUT ANY WARRANTY.  No author or distributor accepts responsibility
  8. to anyone for the consequences of using it or for whether it serves any
  9. particular purpose or works at all, unless he says so in writing.  Refer
  10. to the Ghostscript General Public License for full details.
  11.  
  12. Everyone is granted permission to copy, modify and redistribute
  13. Ghostscript, but only under the conditions described in the Ghostscript
  14. General Public License.  A copy of this license is supposed to have been
  15. given to you along with Ghostscript so you can know your rights and
  16. responsibilities.  It should be in a file named COPYING.  Among other
  17. things, the copyright notice and this notice must be preserved on all
  18. copies.  */
  19.  
  20. /* zchar.c */
  21. /* Character operators for Ghostscript */
  22. #include "ghost.h"
  23. #include "errors.h"
  24. #include "oper.h"
  25. #include "gxfixed.h"            /* for gstype1.h */
  26. #include "gxmatrix.h"            /* for font.h */
  27. #include "gschar.h"
  28. #include "gstype1.h"
  29. #include "gxdevice.h"            /* for gxfont.h */
  30. #include "gxfont.h"
  31. #include "gzpath.h"            /* for type1addpath: see below */
  32. #include "gzstate.h"
  33. #include "alloc.h"
  34. #include "dict.h"
  35. #include "font.h"
  36. #include "estack.h"
  37. #include "state.h"
  38. #include "store.h"
  39.  
  40. /* All the character rendering operators use the execution stack */
  41. /* for loop control -- see estack.h for details. */
  42. /* The information pushed by these operators is as follows: */
  43. /*    the enumerator (t_string, but points to a gs_show_enum); */
  44. /*    a slot for the procedure for kshow, unused otherwise; */
  45. /*    the procedure to be called at the end of the enumeration */
  46. /*        (t_operator, but called directly, not by the interpreter); */
  47. /*    the usual e-stack mark (t_null). */
  48. #define snumpush 4
  49. #define senum (gs_show_enum *)(esp->value.bytes)
  50. #define sslot esp[-1]
  51. #define seproc esp[-2]
  52.  
  53. /* Imports */
  54. extern int array_get(P3(ref *, long, ref *));
  55. extern ref name_StandardEncoding;
  56.  
  57. /* Forward references */
  58. private int setup_show(P3(ref *, op_proc_p, int));
  59. private int show_continue(P1(os_ptr));
  60. private int i_show_continue;
  61. private int finish_show(P1(os_ptr));
  62. private int i_finish_show;
  63. private int finish_stringwidth(P1(os_ptr));
  64. private int i_finish_stringwidth;
  65. private gs_show_enum *find_show();
  66. private void free_show();
  67.  
  68. /* show */
  69. int
  70. zshow(register os_ptr op)
  71. {    int code = setup_show(op, finish_show, i_finish_show);
  72.     if ( code < 0 ) return code;
  73.     if ( (code = gs_show_n_init(senum, igs, (char *)op->value.bytes, r_size(op))) < 0 )
  74.        {    free_show();
  75.         return code;
  76.        }
  77.     pop(1);  op--;
  78.     return show_continue(op);
  79. }
  80.  
  81. /* ashow */
  82. int
  83. zashow(register os_ptr op)
  84. {    int code;
  85.     float axy[2];
  86.     if (    (code = num_params(op - 1, 2, axy)) < 0 ||
  87.         (code = setup_show(op, finish_show, i_finish_show)) < 0
  88.        )
  89.         return code;
  90.     if ( (code = gs_ashow_n_init(senum, igs, axy[0], axy[1], (char *)op->value.bytes, r_size(op))) < 0 )
  91.        {    free_show();
  92.         return code;
  93.        }
  94.     pop(3);  op -= 3;
  95.     return show_continue(op);
  96. }
  97.  
  98. /* widthshow */
  99. int
  100. zwidthshow(register os_ptr op)
  101. {    int code;
  102.     float cxy[2];
  103.     check_type(op[-1], t_integer);
  104.     if ( (ulong)(op[-1].value.intval) > 255 ) return e_rangecheck;
  105.     if (    (code = num_params(op - 2, 2, cxy)) < 0 ||
  106.         (code = setup_show(op, finish_show, i_finish_show)) < 0
  107.        )
  108.         return code;
  109.     if ( (code = gs_widthshow_n_init(senum, igs, cxy[0], cxy[1],
  110.                      (char)op[-1].value.intval,
  111.                      (char *)op->value.bytes,
  112.                      r_size(op))) < 0 )
  113.        {    free_show();
  114.         return code;
  115.        }
  116.     pop(4);  op -= 4;
  117.     return show_continue(op);
  118. }
  119.  
  120. /* awidthshow */
  121. int
  122. zawidthshow(register os_ptr op)
  123. {    int code;
  124.     float cxy[2], axy[2];
  125.     check_type(op[-3], t_integer);
  126.     if ( (ulong)(op[-3].value.intval) > 255 ) return e_rangecheck;
  127.     if (    (code = num_params(op - 4, 2, cxy)) < 0 ||
  128.         (code = num_params(op - 1, 2, axy)) < 0 ||
  129.         (code = setup_show(op, finish_show, i_finish_show)) < 0
  130.        )
  131.         return code;
  132.     if ( (code = gs_awidthshow_n_init(senum, igs, cxy[0], cxy[1],
  133.                       (char)op[-3].value.intval,
  134.                       axy[0], axy[1],
  135.                       (char *)op->value.bytes,
  136.                       r_size(op))) < 0 )
  137.        {    free_show();
  138.         return code;
  139.        }
  140.     pop(6);  op -= 6;
  141.     return show_continue(op);
  142. }
  143.  
  144. /* kshow */
  145. int
  146. zkshow(register os_ptr op)
  147. {    int code;
  148.     check_proc(op[-1]);
  149.     if ( (code = setup_show(op, finish_show, i_finish_show)) < 0 ) return code;
  150.     if ( (code = gs_kshow_n_init(senum, igs, (char *)op->value.bytes, r_size(op))) < 0 )
  151.        {    free_show();
  152.         return code;
  153.        }
  154.     sslot = op[-1];        /* save kerning proc */
  155.     pop(2);  op -= 2;
  156.     return show_continue(op);
  157. }
  158.  
  159. /* Common finish procedure for all show operations. */
  160. /* Doesn't have to do anything. */
  161. private int
  162. finish_show(os_ptr op)
  163. {    return 0;
  164. }
  165.  
  166. /* stringwidth */
  167. int
  168. zstringwidth(register os_ptr op)
  169. {    int code = setup_show(op, finish_stringwidth, i_finish_stringwidth);
  170.     if ( code < 0 ) return code;
  171.     if ( (code = gs_stringwidth_n_init(senum, igs, (char *)op->value.bytes, r_size(op))) < 0 )
  172.        {    free_show();
  173.         return code;
  174.        }
  175.     pop(1);  op--;
  176.     return show_continue(op);
  177. }
  178. /* Finishing procedure for stringwidth. */
  179. /* Pushes the accumulated width. */
  180. private int
  181. finish_stringwidth(register os_ptr op)
  182. {    gs_point width;
  183.     gs_show_width(senum, &width);
  184.     push(2);
  185.     make_real(op - 1, width.x);
  186.     make_real(op, width.y);
  187.     return 0;
  188. }
  189.  
  190. /* charpath */
  191. int
  192. zcharpath(register os_ptr op)
  193. {    int code;
  194.     check_type(*op, t_boolean);
  195.     code = setup_show(op - 1, finish_show, i_finish_show);
  196.     if ( code < 0 ) return code;
  197.     if ( (code = gs_charpath_n_init(senum, igs, (char *)op[-1].value.bytes, r_size(op - 1), op->value.index)) < 0 )
  198.        {    free_show();
  199.         return code;
  200.        }
  201.     pop(2);  op -= 2;
  202.     return show_continue(op);
  203. }
  204.  
  205. /* setcachedevice */
  206. int
  207. zsetcachedevice(register os_ptr op)
  208. {    float wbox[6];
  209.     int npop = 6;
  210.     gs_show_enum *penum = find_show();
  211.     int code = num_params(op, 6, wbox);
  212.     if ( penum == 0 ) return e_undefined;
  213.     if ( code < 0 )
  214.        {    /* P*stScr*pt implementations apparently allow the */
  215.         /* bounding box to be specified as a 4-element array. */
  216.         /* Check for this here. */
  217.         check_array(*op);
  218.         if ( r_size(op) != 4 ||
  219.              num_params(op - 1, 2, wbox) < 0 ||
  220.              num_params(op->value.refs + 3, 4, wbox + 2) < 0
  221.            )
  222.             return code;
  223.         npop = 3;
  224.        }
  225.     if ( (code = gs_setcachedevice(penum, igs, wbox[0], wbox[1], wbox[2], wbox[3], wbox[4], wbox[5])) < 0 )
  226.         return code;
  227.     pop(npop);
  228.     return 0;
  229. }
  230.  
  231. /* setcharwidth */
  232. int
  233. zsetcharwidth(register os_ptr op)
  234. {    float width[2];
  235.     gs_show_enum *penum = find_show();
  236.     int code = num_params(op, 2, width);
  237.     if ( penum == 0 ) return e_undefined;
  238.     if (    code < 0 || 
  239.         (code = gs_setcharwidth(penum, igs, width[0], width[1])) < 0
  240.        )
  241.         return code;
  242.     pop(2);
  243.     return 0;
  244. }
  245.  
  246. /* setmetrics */
  247. int
  248. zsetmetrics(register os_ptr op)
  249. {    float params[4];
  250.     gs_point sb, w;
  251.     gs_show_enum *penum = find_show();
  252.     int code, size;
  253.     if ( penum == 0 ) return e_undefined;
  254.     switch ( r_type(op) )
  255.        {
  256.     case t_array:
  257.         switch ( (size = r_size(op)) )
  258.            {
  259.         case 2: case 4: break;
  260.         default: return e_invalidfont;
  261.            }
  262.         code = num_params(op->value.refs + size - 1, size, params);
  263.         if ( code < 0 ) return code;
  264.         sb.x = params[0];
  265.         if ( size == 4 )
  266.             sb.y = params[1], w.x = params[2], w.y = params[3];
  267.         else
  268.             sb.y = 0, w.x = params[1], w.y = 0;
  269.         code = gs_setmetrics(penum, igs, &sb, &w);
  270.         break;
  271.     default:
  272.         code = real_param(op, params);
  273.         if ( code < 0 ) return code;
  274.         w.x = params[0];
  275.         w.y = 0;
  276.         code = gs_setmetrics(penum, igs, 0, &w);
  277.        }
  278.     if ( code >= 0 ) pop(1);
  279.     return code;
  280. }
  281.  
  282. /* type1addpath */
  283. typedef struct {
  284.     gs_font *pfont;
  285.     fixed *osptr;            /* fake interpreter operand stack */
  286.     fixed ostack[2];
  287. } z1_data;
  288. int
  289. ztype1addpath(register os_ptr op)
  290. {    int code, value;
  291.     gs_show_enum *penum = find_show();
  292.     gs_font *pfont = gs_currentfont(igs);
  293.     font_data *pfdata = (font_data *)pfont->client_data;
  294.     gs_type1_state *pis;
  295.     fixed discard;
  296.     gs_fixed_point spt, ept;
  297.     int flex_path_was_open;
  298.     gs_type1_data tdata;
  299.     z1_data zdata;
  300.     byte *charstring = 0;
  301.     ref enc_entry;
  302.     if ( penum == 0 ) return e_undefined;
  303.     check_type(*op, t_string);
  304.     tdata = pfont->data.base.type1_data;
  305.     zdata.pfont = pfont;
  306.     zdata.osptr = zdata.ostack;
  307.     tdata.proc_data = (char *)&zdata;
  308.     if ( r_size(op) <= tdata.lenIV )
  309.        {    /* String is empty, or too short.  Just ignore it. */
  310.         pop(1);
  311.         return 0;
  312.        }
  313.     pis = (gs_type1_state *)alloc(1, gs_type1_state_sizeof, "type1addpath");
  314.     if ( pis == 0 ) return e_VMerror;
  315.     code = gs_type1_init(pis, penum,
  316.                  gs_show_in_charpath(penum), tdata.PaintType,
  317.                  &tdata);
  318.     if ( code < 0 )
  319.        {    alloc_free((char *)pis, 1, gs_type1_state_sizeof, "type1addpath");
  320.         return code;
  321.        }
  322.     charstring = op->value.bytes;
  323. more:    code = gs_type1_interpret(pis, charstring, &value);
  324.     charstring = 0;
  325.     switch ( code )
  326.        {
  327.     case type1_result_seac:
  328.        {    ref *pstdenc, *pcstr;
  329.         if ( dict_find(&systemdict,
  330.                    &name_StandardEncoding, &pstdenc) <= 0 )
  331.             return e_undefined;
  332.         code = array_get(pstdenc, (long)value, &enc_entry);
  333.         if ( code < 0 ) return code;
  334.         if ( dict_find(&pfdata->CharStrings,
  335.                    &enc_entry, &pcstr) <= 0 )
  336.             return e_undefined;
  337.         if ( !r_has_type(pcstr, t_string) )
  338.             return e_invalidfont;
  339.         charstring = pcstr->value.bytes;
  340.        }    goto more;
  341.     case type1_result_callothersubr:
  342.        {    /* We aren't prepared to call the interpreter here, */
  343.         /* so we fake the Flex feature. */
  344.         gx_path *ppath = igs->path;
  345.         gs_type1_pop(pis, &discard);    /* pop # of args */
  346.         switch ( value )
  347.            {
  348.         case 0:
  349.             /* We have to do something really sleazy here, */
  350.             /* namely, make it look as though the rmovetos */
  351.             /* never really happened, because we don't want */
  352.             /* to interrupt the current subpath. */
  353.             gx_path_current_point(ppath, &ept);
  354.             gx_path_add_point(ppath, spt.x, spt.y);
  355.             ppath->subpath_open = flex_path_was_open;
  356.                     /* ^--- sleaze */
  357.             gx_path_add_line(ppath, ept.x, ept.y);
  358.             /* Transfer endpoint coordinates to 'ostack' */
  359.             gs_type1_pop(pis, &zdata.ostack[0]);
  360.             gs_type1_pop(pis, &zdata.ostack[1]);
  361.             gs_type1_pop(pis, &discard);
  362.             zdata.osptr = &zdata.ostack[2];
  363.             goto more;
  364.         case 1:
  365.             gx_path_current_point(ppath, &spt);
  366.             flex_path_was_open = ppath->subpath_open;
  367.                     /* ^--- more sleaze */
  368.             goto more;
  369.         case 2:
  370.             goto more;
  371.         case 3:
  372.             gs_type1_pop(pis, &discard);    /* pop subr# */
  373.             zdata.ostack[0] = int2fixed(3);
  374.             zdata.osptr = &zdata.ostack[1];
  375.             goto more;
  376.            }
  377.         /* Unrecognized othersubr */
  378.         code = e_rangecheck;
  379.        }    break;
  380.        }
  381.     alloc_free((char *)pis, 1, gs_type1_state_sizeof, "type1addpath");
  382.     if ( code >= 0 ) pop(1);
  383.     return code;
  384. }
  385.  
  386. /* type1imagepath */
  387. int
  388. ztype1imagepath(register os_ptr op)
  389. {    float woxy[4];
  390.     int code;
  391.     check_type(op[-7], t_string);
  392.     check_type(op[-6], t_integer);
  393.     check_type(op[-5], t_integer);
  394.     if ( (code = num_params(op - 1, 4, woxy)) < 0 ) return code;
  395.     check_write_type(*op, t_string);
  396.     code = gs_type1imagepath(igs, op[-7].value.bytes,
  397.         (int)op[-6].value.intval, (int)op[-5].value.intval,
  398.         woxy[0], woxy[1], woxy[2], woxy[3],
  399.         op->value.bytes, r_size(op));
  400.     if ( code < 0 ) return code;
  401.     op[-7] = *op;
  402.     r_set_size(op - 7, code);
  403.     pop(7);
  404.     return 0;
  405. }
  406.  
  407. /* ------ Auxiliary procedures for type 1 fonts ------ */
  408.  
  409. int
  410. z1_subr_proc(gs_type1_data *pdata, int index, byte **pstr)
  411. {    gs_font *pfont = ((z1_data *)(pdata->proc_data))->pfont;
  412.     font_data *pfdata = (font_data *)(pfont->client_data);
  413.     ref *psubr;
  414.     if ( index < 0 || index >= r_size(&pfdata->Subrs) )
  415.         return e_rangecheck;
  416.     psubr = pfdata->Subrs.value.refs + index;
  417.     check_type(*psubr, t_string);
  418.     *pstr = psubr->value.bytes;
  419.     return 0;
  420. }
  421.  
  422. int
  423. z1_pop_proc(gs_type1_data *pdata, fixed *pf)
  424. {    *pf = *--(((z1_data *)(pdata->proc_data))->osptr);
  425.     return 0;
  426. }
  427.  
  428. /* ------ Initialization procedure ------ */
  429.  
  430. op_def zchar_op_defs[] = {
  431.     {"3ashow", zashow},
  432.     {"6awidthshow", zawidthshow},
  433.     {"2charpath", zcharpath},
  434.     {"2kshow", zkshow},
  435.     {"3setcachedevice", zsetcachedevice},
  436.     {"2setcharwidth", zsetcharwidth},
  437.     {"1.setmetrics", zsetmetrics},
  438.     {"1show", zshow},
  439.     {"1stringwidth", zstringwidth},
  440.     {"1type1addpath", ztype1addpath},
  441.     {"8type1imagepath", ztype1imagepath},
  442.     {"4widthshow", zwidthshow},
  443.         /* Internal operators */
  444.     {"0%finish_show", finish_show, &i_finish_show},
  445.     {"0%finish_stringwidth", finish_stringwidth, &i_finish_stringwidth},
  446.     {"0%show_continue", show_continue, &i_show_continue},
  447.     op_def_end(0)
  448. };
  449.  
  450. /* ------ Internal routines ------ */
  451.  
  452. /* Set up for a show operator. */
  453. /* The top stack element must be the string to be scanned. */
  454. /* The caller has already done all other argument checking. */
  455. private int
  456. setup_show(ref *op, op_proc_p endproc /* end procedure */, int proc_index)
  457. {    gs_show_enum *penum;
  458.     check_read_type(*op, t_string);
  459.     check_estack(snumpush + 2);
  460.     if ( (penum = (gs_show_enum *)alloc(1, gs_show_enum_sizeof, "setup_show")) == 0 )
  461.         return e_VMerror;
  462.     mark_estack(es_show);
  463.     push_op_estack(endproc, proc_index);
  464.     ++esp;
  465.     make_tv(esp, t_null, index, 0);        /* reserve slot */
  466.     ++esp;
  467.     make_tasv(esp, t_string, 0, gs_show_enum_sizeof, bytes, (byte *)penum);
  468.     return o_push_estack;
  469. }
  470.  
  471. /* Continuation operator for character rendering. */
  472. private int
  473. show_continue(register os_ptr op)
  474. {    gs_show_enum *penum = senum;
  475.     int code = gs_show_next(penum);
  476.     switch ( code )
  477.        {
  478.     case 0:                /* all done */
  479.         code = (*real_opproc(&seproc))(op);
  480.         free_show();
  481.         return (code >= 0 ? o_pop_estack : code);
  482.     case gs_show_kern:
  483.        {    ref *pslot = &sslot;
  484.         push(2);
  485.         make_int(op - 1, gs_kshow_previous_char(penum));
  486.         make_int(op, gs_kshow_next_char(penum));
  487.         push_op_estack(show_continue, i_show_continue);        /* continue after kerning */
  488.         *++esp = *pslot;    /* kerning procedure */
  489.        }
  490.         return o_push_estack;
  491.     case gs_show_render:
  492.        {    font_data *pfont = (font_data *)gs_currentfont(igs)->client_data;
  493.         push(2);
  494.         op[-1] = pfont->dict;    /* push the font */
  495.         make_int(op, gs_show_current_char(penum));
  496.         push_op_estack(show_continue, i_show_continue);
  497.         *++esp = pfont->BuildChar;
  498.        }
  499.         return o_push_estack;
  500.     default:            /* error */
  501.         free_show();
  502.         return code;
  503.        }
  504. }
  505.  
  506. /* Find the current show enumerator on the e-stack. */
  507. private gs_show_enum *
  508. find_show()
  509. {    es_ptr ep = esp;
  510.     while ( !(r_has_type(ep, t_null) && ep->value.index == es_show) )
  511.        {    if ( --ep < esbot ) return 0;    /* no mark */
  512.        }
  513.     return (gs_show_enum *)ep[snumpush - 1].value.bytes;
  514. }
  515.  
  516. /* Discard the show record (after an error, or at the end). */
  517. private void
  518. free_show()
  519. {    alloc_free((char *)senum, 1, gs_show_enum_sizeof, "free_show");
  520.     esp -= snumpush;
  521. }
  522.